﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using Geotools.Geometries;

namespace AzukiMap.MapSource
{
    public class GoogleMapSource : MercatorQuadTileSource
    {
        const int NUM_OF_LAYERS = 4;

        List<string> _currentBaseUris;
        List<string> _sateliteBaseUris;
        List<string> _mapBaseUris;
        List<string> _labelBaseUris;
        List<string> _terrainBaseUris;

        Dictionary<GoogleMapLayerType, string> _tileVersions;
        Dictionary<GoogleMapLayerType, string> _additionalParams;
        string _locale;

        GoogleMapLayerType _tileType;

        public GoogleMapLayerType TileType
        {
            set { SetTileType(value); }
            get { return _tileType; }
        }

        public override List<string> BaseUris
        {
            get { return _currentBaseUris; }
        }

        public Dictionary<GoogleMapLayerType, string> TileVersions
        {
            get { return _tileVersions; }
            set { _tileVersions = value; }
        }

        public Dictionary<GoogleMapLayerType, string> AdditionalParams
        {
            set { _additionalParams = value; }
            get { return _additionalParams; }
        }

        public string Locale
        {
            get { return _locale; }
            set { _locale = value; }
        }

        public GoogleMapSource(string name)
            : base(name)
        {
            _dpi = 72;
            _tileHeight = 256;
            _tileWidth = 256;

            _sateliteBaseUris = new List<string>(NUM_OF_LAYERS);
            _labelBaseUris = new List<string>(NUM_OF_LAYERS);
            _mapBaseUris = new List<string>(NUM_OF_LAYERS);
            _terrainBaseUris = new List<string>(NUM_OF_LAYERS);
            _tileType = GoogleMapLayerType.MAP;
            _tileVersions = new Dictionary<GoogleMapLayerType, string>(NUM_OF_LAYERS);
            _additionalParams = new Dictionary<GoogleMapLayerType, string>(NUM_OF_LAYERS);
            //_maxExtent = _geoUtil.CreateExtentPolygon(-180, 85.05112878, -180, -85.05112878, 180, -85.05112878, 180, 85.05112878);
            _maxExtent = new GTEnvelope(-180, -85.05112878, 180, 85.05112878);
            _locale = "en";
            _sourceLogo = new Uri("http://maps.google.co.jp/intl/en/images/maps_logo_beta_small_blue.png");

            SetBaseUris();
            SetVersions();
            SetZoomLevels();
            SetScales();
            SetTileType(_tileType);
            SetAdditionalParams();
        }

        void SetBaseUris()
        {
            _sateliteBaseUris.Add("http://khm0.google.co.jp/kh?");
            _sateliteBaseUris.Add("http://khm1.google.co.jp/kh?");
            _sateliteBaseUris.Add("http://khm2.google.co.jp/kh?");
            _sateliteBaseUris.Add("http://khm3.google.co.jp/kh?");

            _labelBaseUris.Add("http://mt1.google.com/mt?");
            _labelBaseUris.Add("http://mt2.google.com/mt?");
            _labelBaseUris.Add("http://mt3.google.com/mt?");
            _labelBaseUris.Add("http://mt4.google.com/mt?");

            _mapBaseUris.Add("http://mt0.google.com/mt?");
            _mapBaseUris.Add("http://mt1.google.com/mt?");
            _mapBaseUris.Add("http://mt2.google.com/mt?");
            _mapBaseUris.Add("http://mt3.google.com/mt?");

            _terrainBaseUris.Add("http://mt3.google.com/mt?");
            _terrainBaseUris.Add("http://mt3.google.com/mt?");
            _terrainBaseUris.Add("http://mt3.google.com/mt?");
            _terrainBaseUris.Add("http://mt3.google.com/mt?");
        }

        void SetVersions()
        {
            _tileVersions.Add(GoogleMapLayerType.SATELITE, "v=33");
            _tileVersions.Add(GoogleMapLayerType.MAP, "v=w2.86");
            _tileVersions.Add(GoogleMapLayerType.LABEL, "v=w2t.86");
            _tileVersions.Add(GoogleMapLayerType.TERRAIN, "v=w2p.87");
        }

        void SetZoomLevels()
        {
            _scaleLevels.Add(295829355.5,1);
            _scaleLevels.Add(147914677.7,2);
            _scaleLevels.Add(73957338.86,3);
            _scaleLevels.Add(36978669.43,4);
            _scaleLevels.Add(18489334.72,5);
            _scaleLevels.Add(9244667.36,6);
            _scaleLevels.Add(4622333.68,7);
            _scaleLevels.Add(2311166.84,8);
            _scaleLevels.Add(1155583.42,9);
            _scaleLevels.Add(577791.71,10);
            _scaleLevels.Add(288895.85,11);
            _scaleLevels.Add(144447.93,12);
            _scaleLevels.Add(72223.96,13);
            _scaleLevels.Add(36111.98,14);
            _scaleLevels.Add(18055.99,15);
            _scaleLevels.Add(9028,16);
            _scaleLevels.Add(4514,17);
            _scaleLevels.Add(2257,18);
            _scaleLevels.Add(1128.5,19);
        }

        void SetScales()
        {
            foreach (KeyValuePair<double, int> level in _scaleLevels)
            {
                _scales.Add(level.Key);
            }
            _scales.Sort();
        }

        void SetAdditionalParams()
        {
            _additionalParams.Add(GoogleMapLayerType.SATELITE, "");
            _additionalParams.Add(GoogleMapLayerType.MAP, "");
            _additionalParams.Add(GoogleMapLayerType.LABEL, "");
            _additionalParams.Add(GoogleMapLayerType.TERRAIN, "");
        }

        void SetTileType(GoogleMapLayerType tileType)
        {
            switch (tileType)
            {
                case GoogleMapLayerType.SATELITE:
                    _tileType = tileType;
                    _currentBaseUris = _sateliteBaseUris;
                    break;
                case GoogleMapLayerType.LABEL:
                    _tileType = tileType;
                    _currentBaseUris = _labelBaseUris;
                    break;
                case GoogleMapLayerType.MAP:
                    _tileType = tileType;
                    _currentBaseUris = _mapBaseUris;
                    break;
                case GoogleMapLayerType.TERRAIN:
                    _tileType = tileType;
                    _currentBaseUris = _terrainBaseUris;
                    break;
                default:
                    // do nothing.
                    break;
            }
        }
    }

    public enum GoogleMapLayerType
    {
        MAP,
        SATELITE,
        LABEL,
        TERRAIN
    }

}
